]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
appDisplay: Add folder title and entry to dialog
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Tue, 17 Dec 2019 19:39:24 +0000 (16:39 -0300)
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Tue, 21 Jan 2020 14:07:08 +0000 (11:07 -0300)
This allows editing the folder name, and keeps the folder title visible
at all times.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/896

data/theme/gnome-shell-sass/widgets/_app-grid.scss
js/ui/appDisplay.js

index f5467bbd6d14c3155ba65064f8932bc1b2e06a20..42aeadc1920434d8e3098d43fd872849df875ae3 100644 (file)
@@ -90,6 +90,33 @@ $app_grid_fg_color: #fff;
   border-radius: 8px;
   spacing: 24px;
   background-color: transparentize(darken($osd_bg_color,10%), 0.05);
+
+  & .folder-name-container {
+    padding: 12px 18px;
+    spacing: 12px;
+
+    & .folder-name-label,
+    & .folder-name-entry {
+      font-size: 18pt;
+      font-weight: bold;
+    }
+
+    & .folder-name-entry { width: 300px }
+
+    /* FIXME: this is to keep the label in sync with the entry */
+    & .folder-name-label { padding: 5px 7px }
+
+    & .edit-folder-button {
+      @extend %button;
+
+      padding: 0;
+      width: 36px;
+      height: 36px;
+      border-radius: 18px;
+
+      & > StIcon { icon-size: 16px }
+    }
+  }
 }
 .app-folder-dialog-container {
   padding: 12px;
index 9f60eef206e33caef323f2356764b0d3b9711b7e..88e34cc6e0e2cb1fce0ec7b44dbacac2a658774a 100644 (file)
@@ -1629,7 +1629,7 @@ var FolderIcon = GObject.registerClass({
         if (this._dialog)
             return;
         if (!this._dialog) {
-            this._dialog = new AppFolderDialog(this);
+            this._dialog = new AppFolderDialog(this, this._folder);
             this._parentView.addFolderDialog(this._dialog);
             this._dialog.connect('open-state-changed', (popup, isOpen) => {
                 if (!isOpen)
@@ -1817,7 +1817,7 @@ var AppFolderDialog = GObject.registerClass({
         'open-state-changed': { param_types: [GObject.TYPE_BOOLEAN] },
     },
 }, class AppFolderDialog extends St.Widget {
-    _init(source) {
+    _init(source, folder) {
         super._init({
             layout_manager: new Clutter.BinLayout(),
             style_class: 'app-folder-dialog-container',
@@ -1833,6 +1833,7 @@ var AppFolderDialog = GObject.registerClass({
         }));
 
         this._source = source;
+        this._folder = folder;
         this._view = source.view;
 
         this._isOpen = false;
@@ -1844,8 +1845,11 @@ var AppFolderDialog = GObject.registerClass({
             y_expand: true,
             x_align: Clutter.ActorAlign.FILL,
             y_align: Clutter.ActorAlign.FILL,
+            vertical: true,
         });
         this.add_child(this._viewBox);
+
+        this._addFolderNameEntry();
         this._viewBox.add_child(this._view);
 
         global.focus_manager.add_group(this);
@@ -1860,6 +1864,134 @@ var AppFolderDialog = GObject.registerClass({
         this._needsZoomAndFade = false;
     }
 
+    _addFolderNameEntry() {
+        this._entryBox = new St.BoxLayout({
+            style_class: 'folder-name-container',
+        });
+        this._viewBox.add_child(this._entryBox);
+
+        // Empty actor to center the title
+        let ghostButton = new Clutter.Actor();
+        this._entryBox.add_child(ghostButton);
+
+        let stack = new Shell.Stack({
+            x_expand: true,
+            x_align: Clutter.ActorAlign.CENTER,
+        });
+        this._entryBox.add_child(stack);
+
+        // Folder name label
+        this._folderNameLabel = new St.Label({
+            style_class: 'folder-name-label',
+            x_expand: true,
+            y_expand: true,
+            x_align: Clutter.ActorAlign.CENTER,
+            y_align: Clutter.ActorAlign.CENTER,
+        });
+
+        stack.add_child(this._folderNameLabel);
+
+        // Folder name entry
+        this._entry = new St.Entry({
+            style_class: 'folder-name-entry',
+            opacity: 0,
+            reactive: false,
+        });
+        this._entry.clutter_text.set({
+            x_expand: true,
+            x_align: Clutter.ActorAlign.CENTER,
+        });
+
+        this._entry.clutter_text.connect('activate', () => {
+            this._showFolderLabel();
+        });
+
+        stack.add_child(this._entry);
+
+        // Edit button
+        this._editButton = new St.Button({
+            style_class: 'edit-folder-button',
+            button_mask: St.ButtonMask.ONE,
+            toggle_mode: true,
+            reactive: true,
+            can_focus: true,
+            x_align: Clutter.ActorAlign.END,
+            y_align: Clutter.ActorAlign.CENTER,
+            child: new St.Icon({
+                icon_name: 'document-edit-symbolic',
+                icon_size: 16,
+            }),
+        });
+
+        this._editButton.connect('notify::checked', () => {
+            if (this._editButton.checked)
+                this._showFolderEntry();
+            else
+                this._showFolderLabel();
+        });
+
+        this._entryBox.add_child(this._editButton);
+
+        ghostButton.add_constraint(new Clutter.BindConstraint({
+            source: this._editButton,
+            coordinate: Clutter.BindCoordinate.SIZE,
+        }));
+
+        this._folder.connect('changed::name', () => this._syncFolderName());
+        this._syncFolderName();
+    }
+
+    _syncFolderName() {
+        let newName = _getFolderName(this._folder);
+
+        this._folderNameLabel.text = newName;
+        this._entry.text = newName;
+    }
+
+    _switchActor(from, to) {
+        to.reactive = true;
+        to.ease({
+            opacity: 255,
+            duration: 300,
+            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+        });
+
+        from.ease({
+            opacity: 0,
+            duration: 300,
+            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+            onComplete: () => {
+                from.reactive = false;
+            },
+        });
+    }
+
+    _showFolderLabel() {
+        if (this._editButton.checked)
+            this._editButton.checked = false;
+
+        this._maybeUpdateFolderName();
+        this._switchActor(this._entry, this._folderNameLabel);
+    }
+
+    _showFolderEntry() {
+        this._switchActor(this._folderNameLabel, this._entry);
+
+        this._entry.clutter_text.set_selection(0, -1);
+        this._entry.clutter_text.grab_key_focus();
+    }
+
+    _maybeUpdateFolderName() {
+        let folderName = _getFolderName(this._folder);
+        let newFolderName = this._entry.text.trim();
+
+        if (newFolderName.length === 0 || newFolderName === folderName)
+            return;
+
+        this._folder.set_string('name', newFolderName);
+        this._folder.set_boolean('translate', false);
+    }
+
     _zoomAndFadeIn() {
         let [sourceX, sourceY] =
             this._source.get_transformed_position();
@@ -1944,7 +2076,13 @@ var AppFolderDialog = GObject.registerClass({
 
     vfunc_allocate(box, flags) {
         let contentBox = this.get_theme_node().get_content_box(box);
-        this._view.adaptToSize(contentBox.get_width(), contentBox.get_height());
+
+        let [, entryBoxHeight] = this._entryBox.get_size();
+        let spacing = this._viewBox.layout_manager.spacing;
+
+        this._view.adaptToSize(
+            contentBox.get_width(),
+            contentBox.get_height() - entryBoxHeight - spacing);
 
         super.vfunc_allocate(box, flags);
 
@@ -2027,6 +2165,7 @@ var AppFolderDialog = GObject.registerClass({
             return;
 
         this._zoomAndFadeOut();
+        this._showFolderLabel();
 
         this._grabHelper.ungrab({ actor: this });
         this._isOpen = false;